package cn.com.pc.content.controller;

import cn.com.pc.aaa.Constants;
import cn.com.pc.aaa.model.Identity;
import cn.com.pc.content.annotation.LogRequired;
import cn.com.pc.content.domain.Biz;
import cn.com.pc.content.domain.Site;
import cn.com.pc.content.domain.audit.AuditStatus;
import cn.com.pc.content.domain.content.ContentType;
import cn.com.pc.content.domain.customizedContent.CustomizedContent;
import cn.com.pc.content.domain.customizedContent.CustomizedContentNotFoundException;
import cn.com.pc.content.dto.*;
import cn.com.pc.content.service.ContentService;
import cn.com.pc.content.util.BeanUtils;
import cn.com.pc.content.util.IpUtils;
import cn.com.pc.content.util.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Map;

/**
 * 定制分类内容 controller
 */
@RestController
@RequestMapping("/customized-content")
@Slf4j
public class CustomizedContentController {

    @Autowired
    private ContentService contentService;

    @Autowired
    private HttpServletRequest request;


    /**
     * 查询内容列表
     * @param site
     * @param biz
     * @param customizedContentForm
     * @param sort
     * @return
     */
    @GetMapping
    public PageResult<?> listCustomizedContentByForm(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute("contentType")ContentType contentType, CustomizedContentForm customizedContentForm, Sort sort, @RequestBody(required = false) JsonNode json) {
        customizedContentForm.setSite(site);
        customizedContentForm.setBiz(biz);

        if (json != null && json.get("metaData") != null && json.get("metaData").isObject()) {
            customizedContentForm.setMetaData(JsonUtils.jsonToObj(JsonUtils.obj2String(json.get("metaData")), new TypeReference<Map<String, Object>>(){}));
        }
        return contentService.listContentByForm(customizedContentForm, sort, contentType);
    }


    /**
     * 查询内容详情
     * @param site
     * @param biz
     * @param contentId
     * @return
     */
    @GetMapping("/{contentId:\\w+}")
    public CustomizedContentDTO getCustomizedContent(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute("contentType")ContentType contentType, @PathVariable("contentId") String contentId) {
        CustomizedContentDTO customizedContent = (CustomizedContentDTO) contentService.getContent(contentId, site, biz, contentType);
        if (customizedContent == null) {
            throw new CustomizedContentNotFoundException();
        }
        return customizedContent;
    }


    /**
     * 从所有内容类型中查询内容详情
     * @return
     */
    @GetMapping("/detail")
    public ObjectNode getCustomizedContentDetail(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute(value = "contentType", required = false)ContentType contentType, @RequestParam(value = "referId") String referId, @RequestParam(value = "limit", defaultValue = "5", required = false) int limit) {
        ObjectNode content = contentService.getContentDetail(site, biz, contentType, referId, limit);
        if (content == null) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "内容不存在");
        }
        return content;
    }


    /**
     * 新增内容
     * @param site 站点
     * @param biz 业务
     * @param customizedContentDTO 内容实体
     * @return
     * @throws IOException
     */
    @PostMapping
    @LogRequired(operation = "'新增' + #contentType.getFullname() + #_return")
    public String createCustomizedContent(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute("biz") Biz biz, @RequestAttribute("contentType")ContentType contentType, @Validated @RequestBody CustomizedContentDTO customizedContentDTO){
        // 查重
        CustomizedContent customizedContent
                = (CustomizedContent) contentService.getContentByReferId(customizedContentDTO.getReferId(), site, biz, contentType);
        if (customizedContent != null) {
            customizedContentDTO.setUpdatedBy(identity.getName());
            customizedContentDTO.setUpdatedAt(LocalDateTime.now());
            customizedContentDTO.setIp(IpUtils.getIp(request));
            customizedContent = (CustomizedContent) contentService.updateContent(customizedContentDTO, customizedContent, contentType);
            return customizedContent.getId();
        }

        customizedContentDTO.setSite(site);
        customizedContentDTO.setBiz(biz);
        customizedContentDTO.setContentType(contentType);
        customizedContentDTO.setCreatedAt(LocalDateTime.now());
        customizedContentDTO.setCreatedBy(identity.getName());
        customizedContentDTO.setUpdatedAt(LocalDateTime.now());
        customizedContentDTO.setUpdatedBy(identity.getName());
        customizedContentDTO.setIp(IpUtils.getIp(request));

        customizedContent = new CustomizedContent();
        customizedContent = (CustomizedContent) contentService.createContent(customizedContentDTO, customizedContent, contentType);
        return customizedContent.getId();
    }


    /**
     * 修改内容
     * @param site
     * @param biz
     * @param contentId
     * @param customizedContentDTO
     * @return
     */
    @PutMapping("/{contentId:\\w+}")
    @LogRequired(operation = "'修改' + #contentType.getFullname() + #contentId")
    public CustomizedContent updateCustomizedContent(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute("contentType")ContentType contentType, @PathVariable("contentId") String contentId, @Validated @RequestBody CustomizedContentDTO customizedContentDTO) {
        // 判空
        CustomizedContent customizedContent = (CustomizedContent) contentService.getContentById(contentId, contentType);
        if(customizedContent == null || customizedContent.getSite() != site) {
            throw new CustomizedContentNotFoundException();
        }

        customizedContentDTO.setContentType(contentType);
        customizedContentDTO.setUpdatedBy(identity.getName());
        customizedContentDTO.setUpdatedAt(LocalDateTime.now());
        customizedContentDTO.setIp(IpUtils.getIp(request));
        try {
            request.setAttribute("operation", "，修改属性" + BeanUtils.comparePropertyIgnore(customizedContent, customizedContentDTO, "id", "ip", "auditStatus", "risk", "statData", "createdAt", "createdBy", "updatedAt", "updatedBy", "onShelve", "contentType"));
        } catch (Exception e) {
            log.warn("{}{}生成修改日志有误", contentType.getFullname(), contentId);
            e.printStackTrace();
        }
        return (CustomizedContent) contentService.updateContent(customizedContentDTO, customizedContent, contentType);
    }


    /**
     * 部分修改内容
     * @param site
     * @param biz
     * @param customizedContentDTO
     * @return
     */
    @PatchMapping
    @LogRequired(operation = "'部分修改' + #contentType.getFullname() + #_return.getId()")
    public CustomizedContent partialUpdateCustomizedContent(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute("contentType")ContentType contentType, @RequestBody CustomizedContentDTO customizedContentDTO) {
        // 判空
        String referId = customizedContentDTO.getReferId();
        String id = customizedContentDTO.getId();
        CustomizedContent customizedContent = null;
        if (StringUtils.hasLength(referId) && biz != null) {
            customizedContent = (CustomizedContent) contentService.getContentByReferId(referId, site, biz, contentType);
        } else if (StringUtils.hasLength(id)){
            customizedContent = (CustomizedContent) contentService.getContentById(id, contentType);
        }

        if(customizedContent == null) {
            throw new CustomizedContentNotFoundException();
        }

        customizedContentDTO.setContentType(contentType);
        customizedContentDTO.setUpdatedBy(identity.getName());
        customizedContentDTO.setUpdatedAt(LocalDateTime.now());
        customizedContentDTO.setIp(IpUtils.getIp(request));
        return (CustomizedContent) contentService.partialUpdateContent(customizedContentDTO, customizedContent, contentType);
    }


    /**
     * 上下架内容
     * @param site
     * @param biz
     * @param contentId
     */
    @PatchMapping("/{contentId:\\w+}")
    @LogRequired(operation = "(#json.get('onShelve').asBoolean() == true ? '上架' : '下架') + #contentType.getFullname() + #postId")
    public CustomizedContent shelveCustomizedContent(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute(value = "site", required = false) Site site, @RequestAttribute("biz") Biz biz, @RequestAttribute("contentType")ContentType contentType, @PathVariable("contentId") String contentId, @RequestBody JsonNode json) {
        if (json.get("onShelve") == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "onShelve不能为空");
        }
        boolean onShelve = json.get("onShelve").asBoolean();

        // 判空
        CustomizedContent customizedContent = (CustomizedContent) contentService.getContentById(contentId, contentType);
        if(customizedContent == null || customizedContent.getSite() != site) {
            throw new CustomizedContentNotFoundException();
        }

        if (customizedContent.isOnShelve() == onShelve) {
            return customizedContent;
        }

        if (onShelve && customizedContent.getAuditStatus() != AuditStatus.Publish) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "内容未发布");
        }

        customizedContent.setCreatedBy(identity.getName());
        customizedContent.setCreatedAt(LocalDateTime.now());
        customizedContent.setOnShelve(onShelve);
        return (CustomizedContent) contentService.shelveContent(customizedContent, contentType);
    }


    /**
     * 删除内容
     * @param site
     * @param biz
     * @param contentId
     */
    @DeleteMapping("/{contentId:\\w+}")
    @LogRequired(operation = "'删除' + #contentType.getFullname() + #postId")
    public void deleteCustomizedContent(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute("contentType")ContentType contentType, @PathVariable("contentId") String contentId) {
        // 判空
        CustomizedContent customizedContent = (CustomizedContent) contentService.getContentById(contentId, contentType);
        if(customizedContent == null || customizedContent.getSite() != site) {
            throw new CustomizedContentNotFoundException();
        }

        customizedContent.setCreatedBy(identity.getName());
        customizedContent.setCreatedAt(LocalDateTime.now());
        contentService.deleteContent(customizedContent, contentType);
    }


    /**
     * 内容打标签
     * @param site
     * @param biz
     * @param contentId
     * @param contentDTO
     * @return
     */
    @PutMapping("/{contentId:\\w+}/tags")
    @LogRequired(operation = "#contentType.getFullname() + '打标签' + #contentId")
    public CustomizedContent updateCustomizedContentTag(@RequestAttribute(Constants.AAA_IDENTITY) Identity identity, @RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestAttribute("contentType")ContentType contentType, @PathVariable("contentId") String contentId, @RequestBody CustomizedContentDTO contentDTO) {
        if (CollectionUtils.isEmpty(contentDTO.getTagIds())) {
            contentDTO.setTagIds(new HashSet<>() {});
        }
        // 判空
        CustomizedContent customizedContent = (CustomizedContent) contentService.getContentById(contentId, contentType);
        if(customizedContent == null || customizedContent.getSite() != site) {
            throw new CustomizedContentNotFoundException();
        }

        customizedContent.setUpdatedBy(identity.getName());
        customizedContent.setUpdatedAt(LocalDateTime.now());
        try {
            request.setAttribute("operation", "，修改属性" + BeanUtils.comparePropertyWith(customizedContent, contentDTO, "tagIds"));
        } catch (Exception e) {
            log.warn(contentType.getFullname() + "{}生成修改日志有误", contentId);
            e.printStackTrace();
        }
        return (CustomizedContent) contentService.updateContentTag(customizedContent, contentDTO, contentType);
    }


    /**
     * 召回内容
     * @param tagIdAndWeight
     * @param pageForm
     * @return
     */
    @PostMapping("/recall")
    public PageResult<?> recallItems(@RequestAttribute("site") Site site, @RequestAttribute(value = "biz", required = false) Biz biz, @RequestBody Map<Integer, Integer> tagIdAndWeight, PageForm pageForm, @RequestAttribute("contentType")ContentType contentType) {
        return contentService.listRecallContent(site, contentType, tagIdAndWeight, pageForm.getPageNum(), pageForm.getPageSize());
    }
}
